package se.webbzon.boltzmann.input;

import java.util.ArrayList;
import java.util.Collection;

public abstract class Input {
		
	// A collection of all listeners to this game input
	private Collection<InputListener> listeners;
								
	/*============================================================
	Constructors
	============================================================*/
	
	/** Creates a new abstract game input. **/
	public Input() {
		listeners = new ArrayList<InputListener>();
	}
	
	/*============================================================
	Public Methods
	============================================================*/
	
	/** Adds a listener to this game input. **/
	public boolean addListener(InputListener listener) {
		return listeners.add(listener);
	}
	
	/** Removes a listener from this game input. **/
	public boolean removeListener(InputListener listener) {
		return listeners.remove(listener);
	}
	
	/** Clears all listeners from this game input. **/
	public void clearListeners() {
		listeners.clear();
	}
								
	/** Returns the name of the game input. **/
	public abstract String getName();
	
	/** Returns true if the game input has a physical primary axis. 
	 * Subclasses which supports a primary axis should override this method. **/
	public boolean hasPrimaryAxis() {
		return false;
	}
	
	/** Returns the information associated with the primary axis. 
	 * Subclasses which supports a primary axis should override this method. **/
	public AxisInfo getPrimaryAxisInfo() {
		return null;
	}
	
	/** Returns true if the game input has a physical secondary axis. 
	 * Subclasses which supports a secondary axis should override this method. **/
	public boolean hasSecondaryAxis() {
		return false;
	}
	
	/** Returns the information associated with the secondary axis. 
	 * Subclasses which supports a secondary axis should override this method. **/
	public AxisInfo getSecondaryAxisInfo() {
		return null;
	}
	
	/** Returns the information associated with the given button. **/
	public abstract ButtonInfo getButtonInfo(Button button);
	
	/** Returns true if the given button may be bounded by using
	 * the method bind(). **/
	public abstract boolean supportsBinding(Button button);
	
	/** Binds the next incoming input to the given button. This method will
	 * return true if the binding thread was successfully started. **/
	public abstract boolean startBinding(Button button);
	
	/** Stops all current binding threads. Returns true if the stop method
	 * was successfully executed. **/
	public abstract boolean stopBindings();
	
	/*============================================================
	Protected Methods
	============================================================*/
	
	/** Sets the value of the primary axis. The direction must be in the
	 * range 0-2*pi and the value must be in the range 0.0-1.0. **/
	protected void setPrimaryAxis(double direction, double value) {
		for (InputListener listener : listeners.toArray(new InputListener[0]))
			listener.primaryAxisChanged(this, direction, value);
	}
	
	/** Sets the value of the secondary axis. The direction must be in the
	 * range 0-2*pi and the value must be in the range 0.0-1.0. **/
	protected void setSecondaryAxis(double direction, double value) {
		for (InputListener listener : listeners.toArray(new InputListener[0]))
			listener.secondaryAxisChanged(this, direction, value);
	}
	
	/** Presses a button on the input. **/
	protected void pressButton(Button button) {
		for (InputListener listener : listeners.toArray(new InputListener[0]))
			listener.buttonPressed(this, button);
	}
	
	/** Releases a button on the input. **/
	protected void releaseButton(Button button) {
		for (InputListener listener : listeners.toArray(new InputListener[0]))
			listener.buttonReleased(this, button);
	}
	
	/** Accepts a button on the input. **/
	protected void acceptBinding(Button button) {
		for (InputListener listener : listeners.toArray(new InputListener[0]))
			listener.bindingAccepted(this, button);
	}

}
